import * as path from 'path';
import * as fs from 'fs-extra';
import { loader } from './loader';
import { readJson } from './script';
import { Config, Swagger, Origin, Rule } from './interface';
import { deepDifInterface } from './util/diff';
import { tsGenerate, lockGenerate, serviceGenerate } from './generator';

interface PickItem {
  label: string;
  type: string;
  [propName: string]: any;
}
const DEFAULT_FILE_NAME = 'api';
// 配置文件
let config: Config = {
  rootPath: '',
  outDir: '',
  typingDir: '',
  fileType: 'ts',
  origins: [],
  rules: [{
    test: 'format',
    use: ['format-loader'],
  }],
  servicesHeader: '',
};

let swagger: Swagger[] = [];

export const initConfig = (filePath: string, rootPath: string) => {
  config = Object.assign(config, fs.readJsonSync(filePath));
  config.rootPath = rootPath;
  config.outDir = path.join(rootPath, config.outDir);
  config.origins.forEach((item: Origin, index: number) => {
    if (!item.name) {
      item.name = `${DEFAULT_FILE_NAME}${index === 0 ? '' : index}`;
    }
  })
}

export const diff = () => {
  const { outDir, origins } = config;
  const diffs = [];
  origins.forEach((item: Origin, index: number) => {
    const lockPath = path.join(outDir, `${item.name}-lock.json`);
    const existsFile = fs.existsSync(lockPath);
    if (existsFile) {
      const newJson = swagger[index].paths;
      const oldJson = fs.readJSONSync(lockPath);
      const list = deepDifInterface(oldJson, newJson);
      diffs.push({
        origins: `数据源${item.name}有${list.length}更新`,
        list,
      });
    }
  })
  return diffs;
}

export const syncHock = async () => {
  console.log('syncHock start');
  const { origins, rootPath, rules } = config;
  const promises = [];
  let loaders = getLoader(rules, 'format');
  origins.forEach((item: Origin) => {
    if (item.rules) {
      loaders = getLoader(item.rules, 'format');
    }
    promises.push(readJson(item.originUrl, rootPath, item.options));
  })
  await Promise.all(promises).then(function (results) {
    results.map(async item => item.paths = await loader(loaders, item.paths));
    swagger = results;
  }).catch(function (e) {
    return e;
  });
  console.log('syncHock end');
}

export const updateHock = async (pickItem: PickItem) => {
  const { outDir, origins } = config;
  origins.forEach((item: Origin, index: number) => {
    const lockPath = path.join(outDir, `${item.name}-lock.json`);
    const existsFile = fs.existsSync(lockPath);
    if (existsFile) {
      // const { label, type } = pickItem;
      // let lockJson = fs.readJSONSync(lockPath);
      // if (label === 'all') {
      //   lockJson = remoteDataJson;
      // } else {
      //   if (type === 'remove') {
      //     delete lockJson[label];
      //   } else {
      //     lockJson[label] = remoteDataJson[label];
      //   }
      // }
      // await serviceGenerate(lockJson, config);
      // await lockGenerate(lockJson, config);
    }
  })
}

export const generateHock = async () => {
  console.log('generateHock start');
  await syncHock();
  const tsPromises = [];
  const servicePromises = [];
  const lockPromises = [];
  swagger.forEach(async (item: Swagger, index: number) => {
    const params = {
      fileName: config.origins[index].name,
      outDir: config.outDir,
      fileType: config.fileType,
      servicesHeader: config.servicesHeader,
    }
    tsPromises.push(tsGenerate(item, config.origins[index], config.typingDir));
    lockPromises.push(lockGenerate(item.paths, params));
  })
  const interfaces = await Promise.all(tsPromises).catch(function (e) {
    return e;
  });
  await Promise.all(lockPromises).catch(function (e) {
    return e;
  });
  swagger.forEach(async (item: Swagger, index: number) => {
    const params = {
      fileName: config.origins[index].name,
      outDir: config.outDir,
      fileType: config.fileType,
      servicesHeader: config.servicesHeader,
      interfaces: interfaces[index] || [],
    }
    servicePromises.push(serviceGenerate(item.paths, params));
  })
  await Promise.all(servicePromises).catch(function (e) {
    return e;
  });
  console.log('generateHock end');
}

const getLoader = (rules: Rule[], test: string) => {
  let loaders = [];

  rules.forEach(item => {
    if (test === item.test) {
      loaders = item.use;
    }
  });

  return loaders;
}
